﻿using Sys;

using System.Silverlight;
using System.Silverlight.Presentation;
using System.Silverlight.Presentation.Animation;
using System;
using seh = Sys.EventHandler;
using sea = Sys.EventArgs;

namespace SBT
{
    public abstract class ScrollBarBase : IScroller
    {
        protected abstract string GetMinusSideMarginProperty();
        protected abstract string GetPlusSideMarginProperty();
        protected abstract double GetBarContainerReferenceSize();
        protected abstract double GetCurrentScroll();
        protected abstract double GetMaxScroll();
        protected abstract double GetContentSize();
        private int m_timeSpan = 25;
        private object m_intervalID;
        private MouseEventHandler m_onMinusDown ;
        private MouseEventHandler m_onMinusUp ;
        private MouseEventHandler m_onPlusDown ;
        private MouseEventHandler m_onPlusUp ;
        public ScrollBarBase()
        {
            m_onMinusDown = OnMinusMouseDown;
            m_onMinusUp = OnMinusMouseUp;
            m_onPlusDown = OnPlusMouseDown;
            m_onPlusUp = OnPlusMouseUp;
        }
        public int TimeSpan
        {
            get { return m_timeSpan; }
            set { m_timeSpan = value; }
        }
        private Button m_minusBtn;
        private Button m_plusBtn;

        public Button MinusBtn
        {
            get
            {
                return m_minusBtn;
            }
            set
            {
                if ((bool)(object)m_minusBtn)
                {
                    m_minusBtn.Element.RemoveEventListener(InputEvent.MouseLeftButtonDown, m_onMinusDown);
                    m_minusBtn.Element.RemoveEventListener(InputEvent.MouseLeftButtonUp, m_onMinusUp);
                }
                m_minusBtn = value;
                if ((bool)(object)m_minusBtn)
                {
                    m_minusBtn.Element.AddEventListener(InputEvent.MouseLeftButtonDown, m_onMinusDown);
                    m_minusBtn.Element.AddEventListener(InputEvent.MouseLeftButtonUp, m_onMinusUp);
                }
            }
        }
        private Button m_bar;
        private Grid m_barContainer;
        public Button Bar { get { return m_bar; } set { m_bar = value; UpdateBar(); OnBarSet(); } }
        protected virtual void OnBarSet()
        {
        }
        public Grid BarContainer { get { return m_barContainer; } set { m_barContainer = value; UpdateBar(); OnBarContainerSet(); } }
        protected virtual void OnBarContainerSet()
        {
        }
        public Button PlusBtn
        {
            get
            {
                return m_plusBtn;
            }
            set
            {
                if ((bool)(object)m_plusBtn)
                {
                    m_plusBtn.Element.RemoveEventListener(InputEvent.MouseLeftButtonDown, m_onPlusDown);
                    m_plusBtn.Element.RemoveEventListener(InputEvent.MouseLeftButtonUp, m_onPlusUp);
                }
                m_plusBtn = value;
                if ((bool)(object)m_plusBtn)
                {
                    m_plusBtn.Element.AddEventListener(InputEvent.MouseLeftButtonDown, m_onPlusDown);
                    m_plusBtn.Element.AddEventListener(InputEvent.MouseLeftButtonUp, m_onPlusUp);
                }
            }
        }

        private void UpdateBar()
        {
            ScrollContainer scrollContainer = ScrollContainer;
            if (scrollContainer != null && m_bar!=null && m_barContainer !=null)
            {
                if (!scrollContainer.IsReady)
                {
                    scrollContainer.add_ready(delegate
                    {
                        UpdateBar();
                    });
                }
                else
                {
                    double barRatio = GetBarRatio();
                    m_bar.SetNamedValue(GetMinusSideMarginProperty(), GetCurrentScroll() / barRatio);
                    m_bar.SetNamedValue(GetPlusSideMarginProperty(), (GetMaxScroll() - GetCurrentScroll()) / barRatio);
                }
            }
        }
        protected virtual void OnMinusMouseDown(object sender, MouseEventArgs args)
        {
            OnMinusTick(null, null);
            m_intervalID = Type.InvokeMethod(null, "setInterval", new seh(OnMinusTick), m_timeSpan);
        }

        protected virtual void OnPlusMouseDown(object sender, MouseEventArgs args)
        {
            OnPlusTick(null, null);
            m_intervalID = Type.InvokeMethod(null, "setInterval", new seh(OnPlusTick), m_timeSpan);
        }

        protected virtual void OnMinusMouseUp(object sender, MouseEventArgs args)
        {
            m_intervalID = Type.InvokeMethod(null, "clearInterval", m_intervalID);
        }

        protected virtual void OnPlusMouseUp(object sender, MouseEventArgs args)
        {
            m_intervalID = Type.InvokeMethod(null, "clearInterval", m_intervalID);
        }


        private void OnPlusTick(object sender, sea args)
        {
            if ((bool)(object)ScrollContainer)
            {
                if (m_plusBtn.IsMouseInner)
                {
                    ApplyPlusTick();
                }
            }
        }
        protected virtual void ApplyPlusTick()
        {
            UpdateBar();
        }
        protected virtual void ApplyMinusTick()
        {
            UpdateBar();
        }
        private void OnMinusTick(object sender, sea args)
        {
            if ((bool)(object)ScrollContainer)
            {
                if (m_minusBtn.IsMouseInner)
                {
                    ApplyMinusTick();
                }
            }
        }


        #region IScroller Members
        private ScrollContainer m_scrollContainer;
        public ScrollContainer ScrollContainer
        {
            get
            {
                return m_scrollContainer;
            }
            set
            {
                if (m_scrollContainer != value)
                {

                    m_scrollContainer = value;
                    m_scrollContainer.add_scrollXChanged((seh)delegate
                    {
                        UpdateBar();
                    });
                    m_scrollContainer.add_scrollYChanged((seh)delegate
                    {
                        UpdateBar();
                    });
                    m_scrollContainer.add_maxScrollYChanged((seh)delegate
                    {
                        UpdateBar();
                    });
                    m_scrollContainer.add_maxScrollXChanged((seh)delegate
                    {
                        UpdateBar();
                    });
                    UpdateBar();
                }
            }
        }
        protected abstract double GetBarRatio();

        #endregion
    }
}